﻿using Base.HrExtendService;
using Basic.HrCollect;
using Basic.HrDAL.Model;
using Basic.HrLocalEvent.Model;
using Basic.HrModel.DB;
using Basic.HrModel.Emp;
using Basic.HrModel.EmpPost;
using Basic.HrModel.EmpTitle;
using Basic.HrRemoteModel;
using Basic.HrRemoteModel.Emp.Model;
using Basic.HrService.Interface;
using WeDonekRpc.Client;
using WeDonekRpc.Helper;
using WeDonekRpc.Model;
using EmpBase = Basic.HrRemoteModel.Emp.Model.EmpBase;

namespace Basic.HrService.lmpl
{
    internal class EmpService : IEmpService
    {
        private readonly IEmpCollect _Service;
        private readonly IEmpTitleCollect _Title;
        private readonly IPostDicItemCollect _Post;
        private readonly IEmpPostCollect _EmpPost;
        private readonly ICompanyCollect _Company;
        private readonly IDeptCollect _Dept;
        private readonly ITitleDicItemCollect _Titles;
        private readonly IFileService _FileService;
        public EmpService ( IEmpCollect service,
            IEmpTitleCollect title,
            IPostDicItemCollect post,
            ITitleDicItemCollect titleDic,
            IEmpPostCollect empPost,
            ICompanyCollect company,
            IFileService file,
            IDeptCollect dept )
        {
            this._EmpPost = empPost;
            this._FileService = file;
            this._Titles = titleDic;
            this._Service = service;
            this._Title = title;
            this._Post = post;
            this._Company = company;
            this._Dept = dept;
        }
        public EmpPostTitle GetPostTitle ( long empId, long deptId )
        {
            string[] post = this._EmpPost.GetEmpDeptPost(empId, deptId, a => a.PostCode);
            string[] title = this._Title.GetEmpDeptTitle(empId, deptId, a => a.TitleCode);
            return new EmpPostTitle
            {
                PostCode = post,
                TitleCode = title
            };
        }
        public void SetEmpHead ( long empId, string head, long fileId )
        {
            var emp = this._Service.Get(empId, a => new
            {
                a.EmpId,
                a.UserHead
            });
            this._Service.SetUserHead(empId, head);
            this._FileService.Save(fileId, empId, emp.UserHead);
        }
        public EmpSelectItem[] GetSelectItems ( SelectGetParam param )
        {
            return this._Service.GetSelectItems(param);
        }

        public EmpBasicDatum[] GetBasics ( long[] empId, long companyId )
        {
            EmpDto[] emps = this._Service.Gets<EmpDto>(empId);
            if ( emps.IsNull() )
            {
                return Array.Empty<EmpBasicDatum>();
            }
            return this._Format(emps, companyId);
        }
        private EmpBasicDatum[] _Format ( EmpDto[] emps, long companyId )
        {
            EmpBasicDatum[] list = emps.ConvertMap<EmpDto, EmpBasicDatum>();
            List<long> deptId = new List<long>(list.Length * 2);
            List<string> post = new List<string>(list.Length);
            long[] empId = new long[list.Length];
            emps.ForEach(( c, i ) =>
            {
                deptId.Add(c.DeptId);
                deptId.Add(c.UnitId);
                empId[i] = c.EmpId;
            });
            EmpTitleDto[] titles = this._Title.GetEmpTitle(empId, companyId);
            EmpPostDto[] posts = this._EmpPost.GetEmpPost(empId, companyId);
            if ( titles.IsNull() && posts.IsNull() )
            {
                Dictionary<long, string> depts = this._Dept.GetDeptName(deptId.Distinct().ToArray());
                list.ForEach(c =>
                {
                    c.Dept = depts.GetValueOrDefault(c.DeptId) + "(" + depts.GetValueOrDefault(c.UnitId) + ")";
                });
                return list;
            }
            else
            {
                long[] deptIds = this._LoadDeptId(titles, posts, deptId);
                Dictionary<long, string> depts = this._Dept.GetDeptName(deptIds);
                Dictionary<string, string> titleName = null;
                Dictionary<string, string> postName = null;
                if ( !titles.IsNull() )
                {
                    titleName = this._Titles.GetTitleNames(titles.Distinct(a => a.TitleCode));
                }
                if ( !posts.IsNull() )
                {
                    postName = this._Post.GetPostName(posts.Distinct(a => a.PostCode));
                }
                list.ForEach(c =>
                {
                    c.Dept = depts.GetValueOrDefault(c.UnitId) + " " + depts.GetValueOrDefault(c.DeptId);
                    if ( titles != null )
                    {
                        c.Title = titles.Convert(a => a.EmpId == c.EmpId, a => new EmpTitle
                        {
                            DeptId = a.DeptId,
                            TitleCode = a.TitleCode,
                            UnitId = a.UnitId,
                            Show = string.Format("{0}({1}) {2}",
                            depts.GetValueOrDefault(a.DeptId),
                            depts.GetValueOrDefault(a.UnitId),
                            titleName.GetValueOrDefault(a.TitleCode))
                        });
                    }
                    if ( posts != null )
                    {
                        c.Post = posts.Convert(a => a.EmpId == c.EmpId, a => new EmpPost
                        {
                            DeptId = a.DeptId,
                            PostCode = a.PostCode,
                            UnitId = a.UnitId,
                            Show = string.Format("{0}({1}) {2}", depts.GetValueOrDefault(a.DeptId),
                            depts.GetValueOrDefault(a.UnitId),
                            postName.GetValueOrDefault(a.PostCode))
                        });
                    }
                });
                return list;
            }
        }
        public PagingResult<EmpBasicDto> QueryEmp ( EmpQuery query, IBasicPage paging )
        {
            EmpDatumDto[] emps = this._Service.Query<EmpDatumDto>(query, paging, out int count);
            if ( emps.IsNull() )
            {
                return new PagingResult<EmpBasicDto>();
            }
            EmpBasicDto[] dtos = this._Format(emps, query.CompanyId);
            return new PagingResult<EmpBasicDto>(dtos, count);
        }
        private EmpBasicDto[] _Format ( EmpDatumDto[] emps, long companyId )
        {
            EmpBasicDto[] list = emps.ConvertMap<EmpDatumDto, EmpBasicDto>();
            List<long> deptId = new List<long>(list.Length * 2);
            long[] empId = new long[list.Length];
            emps.ForEach(( c, i ) =>
            {
                deptId.Add(c.DeptId);
                deptId.Add(c.UnitId);
                empId[i] = c.EmpId;
            });
            EmpTitleDto[] titles = this._Title.GetEmpTitle(empId, companyId);
            EmpPostDto[] posts = this._EmpPost.GetEmpPost(empId, companyId);
            if ( titles.IsNull() && posts.IsNull() )
            {
                Dictionary<long, string> depts = this._Dept.GetDeptName(deptId.Distinct().ToArray());
                list.ForEach(c =>
                {
                    c.Dept = depts.GetValueOrDefault(c.UnitId) + " " + depts.GetValueOrDefault(c.DeptId);
                });
                return list;
            }
            else
            {
                long[] dids = this._LoadDeptId(titles, posts, deptId);
                Dictionary<long, string> deptName = this._Dept.GetDeptName(dids);
                Dictionary<string, string> titleName = null;
                Dictionary<string, string> postName = null;
                if ( !titles.IsNull() )
                {
                    titleName = this._Titles.GetTitleNames(titles.Distinct(a => a.TitleCode));
                }
                if ( !posts.IsNull() )
                {
                    postName = this._Post.GetPostName(posts.Distinct(a => a.PostCode));
                }
                list.ForEach(c =>
                {
                    c.Dept = deptName.GetValueOrDefault(c.UnitId) + " " + deptName.GetValueOrDefault(c.DeptId);
                    if ( titles != null )
                    {
                        EmpTitleDto[] t = titles.FindAll(a => a.EmpId == c.EmpId && a.DeptId == c.DeptId);
                        if ( !t.IsNull() )
                        {
                            c.EntryTitle = new EntryCode
                            {
                                Code = t.ConvertAll(a => a.TitleCode),
                                Name = t.Join(',', a => titleName.GetValueOrDefault(a.TitleCode))
                            };
                        }
                        c.Title = titles.Convert(a => a.EmpId == c.EmpId && a.DeptId != c.DeptId, a => new EmpTitle
                        {
                            DeptId = a.DeptId,
                            TitleCode = a.TitleCode,
                            UnitId = a.UnitId,
                            Show = string.Format("{0}({1}) {2}",
                            deptName.GetValueOrDefault(a.DeptId),
                            deptName.GetValueOrDefault(a.UnitId),
                            titleName.GetValueOrDefault(a.TitleCode))
                        });
                    }
                    if ( posts != null )
                    {
                        EmpPostDto[] t = posts.FindAll(a => a.EmpId == c.EmpId && a.DeptId == c.DeptId);
                        if ( !t.IsNull() )
                        {
                            c.EntryPost = new EntryCode
                            {
                                Code = t.ConvertAll(a => a.PostCode),
                                Name = t.Join(',', a => postName.GetValueOrDefault(a.PostCode))
                            };
                        }
                        c.Post = posts.Convert(a => a.EmpId == c.EmpId && a.DeptId != c.DeptId, a => new EmpPost
                        {
                            DeptId = a.DeptId,
                            PostCode = a.PostCode,
                            UnitId = a.UnitId,
                            Show = string.Format("{0}({1}) {2}", deptName.GetValueOrDefault(a.DeptId),
                            deptName.GetValueOrDefault(a.UnitId),
                            postName.GetValueOrDefault(a.PostCode))
                        });
                    }
                });
                return list;
            }
        }
        public PagingResult<EmpBasicDatum> Query ( EmpQuery query, IBasicPage paging )
        {
            EmpDto[] emps = this._Service.Query<EmpDto>(query, paging, out int count);
            if ( emps.IsNull() )
            {
                return new PagingResult<EmpBasicDatum>(count);
            }
            EmpBasicDatum[] list = this._Format(emps, query.CompanyId);
            return new PagingResult<EmpBasicDatum>(list, count);
        }
        public void Delete ( long id )
        {
            DBEmpList emp = this._Service.Get<DBEmpList>(id);
            this._Service.Delete(emp);
            new EmpLocalEvent(emp).Send("Delete");
        }
        public long Add ( EmpAdd add )
        {
            add.UnitId = this._Dept.GetUnitId(add.DeptId);
            long empId = this._Service.Add(add);
            if ( add.FileId.HasValue )
            {
                this._FileService.Save(add.FileId.Value, empId);
            }
            return empId;
        }
        public bool CheckIsRepeat ( DataRepeatCheck check )
        {
            return this._Service.CheckIsRepeat(check);
        }
        public void SetDatum ( long id, PersonDatum datum )
        {
            DBEmpList emp = this._Service.Get<DBEmpList>(id);
            EmpSetDto dto = datum.ConvertMap<PersonDatum, EmpSetDto>();
            dto.UnitId = emp.UnitId;
            dto.DeptId = emp.DeptId;
            dto.EmpName = emp.EmpName;
            dto.EmpNo = emp.EmpNo;
            dto.UserType = emp.UserType;
            string head = emp.UserHead;
            string[] cols = this._Service.Set(emp, dto);
            if ( !cols.IsNull() )
            {
                new EmpLocalEvent(emp, cols).AsyncSend("Update");
                if ( cols.Contains("UserHead") )
                {
                    this._FileService.Sync(datum.FileId, id, head);
                }
            }
        }
        public void Set ( long id, EmpSet set )
        {
            DBEmpList emp = this._Service.Get<DBEmpList>(id);
            EmpSetDto dto = set.ConvertMap<EmpSet, EmpSetDto>();
            if ( emp.DeptId != dto.DeptId )
            {
                dto.UnitId = this._Dept.GetUnitId(set.DeptId);
            }
            else
            {
                dto.UnitId = emp.UnitId;
            }
            string head = emp.UserHead;
            string[] cols = this._Service.Set(emp, dto);
            if ( !cols.IsNull() )
            {
                new EmpLocalEvent(emp, cols).AsyncSend("Update");
                if ( cols.Contains("UserHead") )
                {
                    this._FileService.Sync(set.FileId, id, head);
                }
            }

        }

        public EmpBasic GetBasic ( long id )
        {
            return this._Service.Get<EmpBasic>(id);
        }
        public EmpData Get ( long id )
        {
            DBEmpList emp = this._Service.Get<DBEmpList>(id);
            EmpData data = emp.ConvertMap<DBEmpList, EmpData>();
            string[] post = this._EmpPost.GetEmpDeptPost(emp.EmpId, emp.DeptId, a => a.PostCode);
            if ( !post.IsNull() )
            {
                data.PostCode = post;
                data.Post = this._Post.GetPostNameList(post);
            }
            data.Dept = this._Dept.GetDeptName(emp.UnitId) + " " + this._Dept.GetDeptName(emp.DeptId);
            data.Company = this._Company.GetName(data.CompanyId);
            string[] title = this._Title.GetTitle(id, emp.DeptId);
            if ( !title.IsNull() )
            {
                data.TitleCode = title;
                data.Title = this._Titles.GetTitleName(title);
            }
            return data;
        }
        public string GetEmpName ( long id )
        {
            return this._Service.GetName(id);
        }
        private long[] _LoadDeptId ( EmpTitleDto[] titles, EmpPostDto[] post, List<long> deptId )
        {
            if ( titles.IsNull() )
            {
                post.ForEach(a =>
                {
                    deptId.Add(a.DeptId);
                    deptId.Add(a.UnitId);
                });
                return deptId.Distinct().ToArray();
            }
            else if ( post.IsNull() )
            {
                titles.ForEach(a =>
                {
                    deptId.Add(a.DeptId);
                    deptId.Add(a.UnitId);
                });
                return deptId.Distinct().ToArray();
            }
            else
            {
                titles.ForEach(a =>
                {
                    deptId.Add(a.DeptId);
                    deptId.Add(a.UnitId);
                });
                post.ForEach(a =>
                {
                    deptId.Add(a.DeptId);
                    deptId.Add(a.UnitId);
                });
                return deptId.Distinct().ToArray();
            }
        }
        public EmpBasicDatum GetEmpBasic ( long id, long companyId )
        {
            EmpDto emp = this._Service.Get<EmpDto>(id);
            EmpTitleDto[] titles = this._Title.GetEmpTitle<EmpTitleDto>(emp.EmpId, companyId);
            EmpPostDto[] post = this._EmpPost.GetEmpPost<EmpPostDto>(emp.EmpId, companyId);
            EmpBasicDatum datum = new EmpBasicDatum
            {
                Dept = this._Dept.GetDeptName(emp.DeptId),
                DeptId = emp.DeptId,
                EmpId = emp.EmpId,
                EmpName = emp.EmpName,
                EmpNo = emp.EmpNo
            };
            if ( post.IsNull() && titles.IsNull() )
            {
                return datum;
            }
            long[] deptId = this._LoadDeptId(titles, post, new List<long>());
            Dictionary<long, string> depts = this._Dept.GetDeptName(deptId);
            if ( !titles.IsNull() )
            {
                Dictionary<string, string> titleName = this._Titles.GetTitleNames(titles.ConvertAll(a => a.TitleCode));
                datum.Title = titles.ConvertAll(a => new EmpTitle
                {
                    DeptId = a.DeptId,
                    TitleCode = a.TitleCode,
                    Show = string.Format("{0}({1}) {2}", depts.GetValueOrDefault(a.DeptId), depts.GetValueOrDefault(a.UnitId), titleName.GetValueOrDefault(a.TitleCode)),
                    UnitId = a.UnitId,
                });
            }
            if ( !post.IsNull() )
            {
                Dictionary<string, string> names = this._Post.GetPostName(post.ConvertAll(a => a.PostCode));
                datum.Post = post.ConvertAll(a => new EmpPost
                {
                    DeptId = a.DeptId,
                    PostCode = a.PostCode,
                    Show = string.Format("{0}({1}) {2}", depts.GetValueOrDefault(a.DeptId), depts.GetValueOrDefault(a.UnitId), names.GetValueOrDefault(a.PostCode)),
                    UnitId = a.UnitId,
                });
            }
            return datum;
        }

        public void SetEmpStatus ( long empId, HrEmpStatus status )
        {
            if ( this._Service.SetStatus(empId, status) && status == HrEmpStatus.禁用 )
            {
                new UserChangeEvent(empId).AsyncSend("EmpDisable");
            }
        }
        public EmpBase[] SearchEmp ( EmpGetQuery param )
        {
            return this._Service.Search<EmpBase>(param);
        }

        public void SetEmpEntry ( long id, EmpEntry datum )
        {
            DBEmpList emp = this._Service.Get<DBEmpList>(id);
            EmpEntrySet set = new EmpEntrySet
            {
                CompanyId = datum.CompanyId,
                DeptId = datum.DeptId,
                IsRetainTitle = datum.IsRetainTitle,
                Post = datum.Post,
                Title = datum.Title
            };
            set.UnitId = this._Dept.GetUnitId(datum.DeptId);
            var titles = this._Title.GetEmpDeptTitle(id, datum.DeptId, a => new
            {
                a.Id,
                a.TitleCode
            });
            if ( !titles.IsNull() )
            {
                set.DropTitleId = titles.Convert(c => !datum.Title.Contains(c.TitleCode), c => c.Id);
            }
            long companyId = emp.CompanyId;
            this._Service.SetEmpEntry(emp, set);
            new EmpEntryEvent(emp, companyId).AsyncSend();
        }

        public Dictionary<long, string> GetEmpName ( long[] ids )
        {
            return this._Service.GetName(ids);
        }
        public EmpUnitDept[] GetsUnitDept ( long[] empId )
        {
            var list = this._Service.Gets(empId, a => new
            {
                a.EmpId,
                a.EmpName,
                a.UnitId,
                a.DeptId
            });
            if ( list.IsNull() )
            {
                return null;
            }
            long[] deptId = new long[list.Length * 2];
            list.ForEach(( c, i ) =>
            {
                int k = i * 2;
                deptId[k] = c.UnitId;
                deptId[k + 1] = c.DeptId;
            });
            Dictionary<long, string> depts = this._Dept.GetDeptName(deptId);
            return list.ConvertAll(a =>
            {
                return new EmpUnitDept
                {
                    EmpName = a.EmpName,
                    EmpId = a.EmpId,
                    UnitDept = depts[a.UnitId] + " " + depts[a.DeptId]
                };
            });
        }
        public EmpInfo GetInfo ( long empId )
        {
            EmpDto dto = this._Service.Get<EmpDto>(empId);
            EmpInfo info = dto.ConvertMap<EmpDto, EmpInfo>();
            info.Dept = this._Dept.GetDeptName(dto.UnitId) + " " + this._Dept.GetDeptName(dto.DeptId);
            return info;
        }

        public EmpInfo[] GetInfos ( long[] empId )
        {
            EmpDto[] list = this._Service.Gets<EmpDto>(empId);
            if ( list.IsNull() )
            {
                return null;
            }
            long[] deptId = new long[list.Length * 2];
            list.ForEach(( c, i ) =>
            {
                int k = i * 2;
                deptId[k] = c.UnitId;
                deptId[k + 1] = c.DeptId;
            });
            Dictionary<long, string> depts = this._Dept.GetDeptName(deptId);
            EmpInfo[] infos = list.ConvertMap<EmpDto, EmpInfo>();
            infos.ForEach(c =>
            {
                c.Dept = depts[c.UnitId] + " " + depts[c.DeptId];
            });
            return infos;
        }

        public T[] Gets<T> ( long[] ids ) where T : class
        {
            return this._Service.Gets<T>(ids);
        }

        public T Get<T> ( long id ) where T : class
        {
            return this._Service.Get<T>(id);
        }

        public string[] GetNames ( long[] ids )
        {
            return this._Service.GetNames(ids);
        }

        public long[] FindEmpId ( EmpFindParam param )
        {
            return this._Service.FindEmpId(param);
        }
    }
}
